﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections;
using TheVerge.Base.Models;

namespace TheVerge.Phone.Controls {
	/// <summary>
	/// Class was designed with the help from the following article:
	/// http://blogs.msdn.com/b/slmperf/archive/2011/06/30/windows-phone-mango-change-listbox-how-to-detect-compression-end-of-scroll-states.aspx
	/// </summary>
	public partial class InfiniteScroller : UserControl {

		#region Dependency Properties
		public DataTemplate ItemTemplate {
			get { return (DataTemplate)GetValue(ItemTemplateProperty); }
			set { SetValue(ItemTemplateProperty, value); }
		}

		public static readonly DependencyProperty ItemTemplateProperty =
				DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(InfiniteScroller), new PropertyMetadata(null));

		public object ItemsSource {
			get { return (object)GetValue(ItemsSourceProperty); }
			set { SetValue(ItemsSourceProperty, value); }
		}
		public static readonly DependencyProperty ItemsSourceProperty =
				DependencyProperty.Register("ItemsSource", typeof(object), typeof(InfiniteScroller), new PropertyMetadata(null));
		
		#endregion

		#region Public Events
		public event EventHandler BottomReached = delegate { };
		public event EventHandler LeftReached = delegate { };
		public event EventHandler RightReached = delegate { };
		public event EventHandler Scrolling = delegate { };
		public event EventHandler TopReached = delegate { };
		#endregion

		private bool alreadyHookedScrollEvents = false;

		public InfiniteScroller() {
			InitializeComponent();
			Loaded += new RoutedEventHandler(InfiniteScroller_Loaded);
		}

		#region Event Handlers
		private void hgroup_CurrentStateChanging(object sender, VisualStateChangedEventArgs e) {
			if (e.NewState.Name == "CompressionLeft") { LeftReached(this, EventArgs.Empty); }
			if (e.NewState.Name == "CompressionRight") { RightReached(this, EventArgs.Empty); }
			if (e.NewState.Name == "NoHorizontalCompression") { }
		}

		private void InfiniteScroller_Loaded(object sender, RoutedEventArgs e) {
			if (alreadyHookedScrollEvents)
				return;

			alreadyHookedScrollEvents = true;
			if (sv != null) {
				// Visual States are always on the first child of the control template 
				FrameworkElement element = VisualTreeHelper.GetChild(sv, 0) as FrameworkElement;
				if (element != null) {
					VisualStateGroup group = FindVisualState(element, "ScrollStates");
					if (group != null) {
						group.CurrentStateChanging += new EventHandler<VisualStateChangedEventArgs>(group_CurrentStateChanging);
					}
					VisualStateGroup vgroup = FindVisualState(element, "VerticalCompression");
					VisualStateGroup hgroup = FindVisualState(element, "HorizontalCompression");
					if (vgroup != null) {
						vgroup.CurrentStateChanging += new EventHandler<VisualStateChangedEventArgs>(vgroup_CurrentStateChanging);
					}
					if (hgroup != null) {
						hgroup.CurrentStateChanging += new EventHandler<VisualStateChangedEventArgs>(hgroup_CurrentStateChanging);
					}
				}
			}
		}

		private void vgroup_CurrentStateChanging(object sender, VisualStateChangedEventArgs e) {
			if (e.NewState.Name == "CompressionTop") { AtTheTop();  }
			if (e.NewState.Name == "CompressionBottom") { AtTheBottom(); }
			if (e.NewState.Name == "NoVerticalCompression") { }
		}

		private void AtTheTop() {
			var vm = DataContext as IVMEntries;
			if (vm != null)
				vm.Refresh();
			TopReached(this, EventArgs.Empty);
		}

		private void AtTheBottom() {
			var vm = DataContext as IVMEntries;
			if (vm != null)
				vm.LoadMore();
			BottomReached(this, EventArgs.Empty);
		}

		private void group_CurrentStateChanging(object sender, VisualStateChangedEventArgs e) {
			if (e.NewState.Name == "Scrolling") { Scrolling(this, EventArgs.Empty); }
		}
		#endregion

		#region Helper Methods
		private UIElement FindElementRecursive(FrameworkElement parent, Type targetType) {
			int childCount = VisualTreeHelper.GetChildrenCount(parent);
			UIElement returnElement = null;
			if (childCount > 0) {
				for (int i = 0; i < childCount; i++) {
					Object element = VisualTreeHelper.GetChild(parent, i);
					if (element.GetType() == targetType) {
						return element as UIElement;
					} else {
						returnElement = FindElementRecursive(VisualTreeHelper.GetChild(parent, i) as FrameworkElement, targetType);
					}
				}
			}
			return returnElement;
		}
		private VisualStateGroup FindVisualState(FrameworkElement element, string name) {
			if (element == null)
				return null;

			IList groups = VisualStateManager.GetVisualStateGroups(element);
			foreach (VisualStateGroup group in groups)
				if (group.Name == name)
					return group;

			return null;
		}
		#endregion
	}
}
